#include "Client.h"
#include <Windows.h>
#include <iostream>

CONSOLE_SCREEN_BUFFER_INFO csbi;


std::wstring s2ws(const std::string& s)
{
 int len;
 int slength = (int)s.length() + 1;
 len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
 wchar_t* buf = new wchar_t[len];
 MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
 std::wstring r(buf);
 delete[] buf;
 return r;
}

void gotoxy ( short x, short y )
{  
	COORD coord = {x, y};
	SetConsoleCursorPosition ( GetStdHandle ( STD_OUTPUT_HANDLE ), coord );
}

void clearLine(int x, int y, int length) {
	string c = " ";
	for(int i=0; i<length; i++) {
		c.append(" ");
	}
	DWORD dwExitCode;
	wstring w = s2ws(c);
	LPCWSTR result = w.c_str();
	
	COORD coord2 = {x,y};			
	WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
}



COORD getxy (  CONSOLE_SCREEN_BUFFER_INFO * csbi)
{
	COORD coord = csbi->dwCursorPosition;
	return coord;
}

Client::Client(string n)
{
	lines = new MyArray<string>();

	x = 1;
	y = 1;

	name = n;
	if( WSAStartup( MAKEWORD(2, 2), &wsaData ) != NO_ERROR )
    {
        cerr<<"Socket Initialization: Error with WSAStartup\n";
        system("pause");
        WSACleanup();
        exit(10);
    }

    //Create a socket
    mySocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

    if ( mySocket == INVALID_SOCKET )
    {
        cerr<<"Socket Initialization: Error creating socket"<<endl;
        system("pause");
        WSACleanup();
        exit(11);
    }
    myBackup = mySocket;
}


Client::~Client(void)
{
	 WSACleanup();
}

bool Client::SendData( char *buffer )
{
    send( mySocket, buffer, strlen( buffer ), 0 );
    return true;
}

bool Client::RecvData( char *buffer, int size )
{
    int i = recv( mySocket, buffer, size, 0 );
    buffer[i] = '\0';
	if(i == -1) {
		return false;
	}
    return true;
}

void Client::ConnectToServer( const char *ipAddress, int port )
{
	cout << "Connectiong to : " << *ipAddress << ":" << port <<endl; 
    myAddress.sin_family = AF_INET;
    myAddress.sin_addr.s_addr = inet_addr( ipAddress );
    myAddress.sin_port = htons( port );
    
    //cout<<"CONNECTED"<<endl;

    if ( connect( mySocket, (SOCKADDR*) &myAddress, sizeof( myAddress ) ) == SOCKET_ERROR )
    {
        cerr<<"ClientSocket: Failed to connect\n";
        system("pause");
        WSACleanup();
        exit(13);
    }
	cout << "Connected" << endl;
	system("cls");
	showGUI();
	Sleep(1000);
	
	//Send My Name To Server
	SendData((char*)name.c_str());
	//START THREAD
	DWORD  m_dwThreadID;
	HANDLE m_hThread;
	m_hThread = CreateThread(0,0,ThreadFunc,this,0,&m_dwThreadID);

	//cout << "Listening for new messages" << endl;
	char recMessage[256];
	string message;
	while(true) {
		gotoxy(1,22);
		cout << "[" << name << "]: ";
		
		int index = 0;
		string message = "";
		
		cin.getline( recMessage, 256, '\n' );
		string s(recMessage);

		if(s == "quit") {
			exit (1);
		}
		else if(s == "" || s == " ") {

		}
		else if(s == "?") {
			print("Hey hey");
			print("Meira hey hey");
		} else {
			string totalM = "[";
			totalM.append(name);
			totalM.append("] ");
			totalM.append(s);
			SendData((char*)totalM.c_str());
			clearLine(name.length() + 4,22,78 - (name.length() + 4));
			Sleep(100);
		}
	}
}

void Client::showGUI() {
	string c = "*";
	DWORD dwExitCode;
	wstring w = s2ws(c);
	LPCWSTR result = w.c_str();
	for(int i = 0; i<24; i++) {
		//Print horizontal lines
		if(i==0) {
			for(int j=1; j<79; j++) {
				
				COORD coord2 = {j,i};
				
				WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
			}
		} else if(i == 21) {
			for(int j=1; j<79; j++) {
				COORD coord2 = {j,i};
				WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
			}
		}
		else if(i == 23) {
			for(int j=1; j<79; j++) {
				COORD coord2 = {j,i};
				WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
			}
		}

		//print vertical line
		COORD coord2 = {0,i};
		WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);

		COORD coord3 = {79,i};
		WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord3,&dwExitCode);
		if(i< 21) {
			COORD coord3 = {65,i};
			WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord3,&dwExitCode);
		}
	}
}

void Client::print(string c) {	
	lines->add(c);

	int thisY = 20;
	int linesPrinted = 0;
	for(int j=lines->size(); j>0; j --) {
		COORD coord2 = {x,thisY};
		DWORD dwExitCode;
		string s = lines->get(j-1);
		wstring w = s2ws(s);
		LPCWSTR result = w.c_str();
		clearLine(x,thisY,63);
		WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
		linesPrinted ++;
		thisY--;
		if(linesPrinted == 20) {
			break;
		}
	}
}

void Client::printUserList(string s) {
	string userList = s.substr(2);
	int index = userList.find_first_of(',');
	int usersOnline = 0;
	string users[20];
	while(index > 0) {
		string user = userList.substr(0,index);
		users[usersOnline] = user;
		userList = userList.substr(index+1);
		index = userList.find_first_of(',');
		usersOnline++;
	}

	for(int y=1;y<21;y++) {
		clearLine(66,y,12);
	}

	for(int y2=0;y2<usersOnline;y2++) {
		string u = users[y2];
		if(u.length() > 12) {
			u = u.substr(0,12);
		}

		COORD coord2 = {67,y2+1};
		DWORD dwExitCode;
		string s = u;
		wstring w = s2ws(s);
		LPCWSTR result = w.c_str();
		WriteConsoleOutputCharacter(GetStdHandle ( STD_OUTPUT_HANDLE ),result,w.length(),coord2,&dwExitCode);
	}
	
}


unsigned long _stdcall Client::ThreadFunc(void * param) {
	//char recMessage[256] = new char[256];
	
	while(true) {
		char* recMessage = new char[256];
		Client* This = (Client*)param;
		bool b = This->RecvData(recMessage,256);
		if(b) {
			string c(recMessage);
			if(c.length() > 3) {
				if(c.substr(0,2) == "U:") {
					This->printUserList(c);
				} else {
					This->print(c);
				}
			} else {
				This->print(c);
			}
			
		} else {
			string c = "Disconnected from server";
			This->print(c);
			c = "Shutting down in 2 sek";
			This->print(c);
			Sleep(2000);
			exit(0);
		}
		delete[] recMessage;
	}
	
	return 0;
}

